import csv
import time
import os
import sys
import datetime
from trading.models import *
from fundinfo.models import *
from analysis.basic_data import *

MONITOR_RATE_UP = 5.0
MONITOR_RATE_DOWN = -5.0

def getTimeStamp(timeStr):
    timeArray = time.strptime(timeStr, "%Y-%m-%d %H:%M:%S")
    timeStamp = int(time.mktime(timeArray))
    return timeStamp

def getDateTimeFromStr(str):
    date = datetime.datetime.strptime(str, "%Y-%m-%d %H:%M:%S")
    return date

def getDateFromStr(str):
    return datetime.datetime.strptime(str, "%Y-%m-%d %H:%M:%S").date()

def getDateTimeFromStr2(str):
    return time.strptime(str, "%Y-%m-%d %H:%M:%S")


def getTimeStr(timeStamp):
    timeArray = time.localtime(timeStamp)
    timeStr = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
    return timeStr

class FundPrice:
    date = ""
    jjjz = 0.0 #基金净值
    ljjz = 0.0 #累计净值
    rate = 0.0 #日增长率
    rateYear = 0.0 #最近1年的收益
    rateYear3 = 0.0 #最近3年的收益
    rateYear5 = 0.0 #最近5年的收益

class FundIncome:
    units = 0.0 #基金份额
    cost = 0.0 # 平均成本
    totalCost = 0.0 # 总成本
    incomeTotal = 0.0 # 累计收益
    income = 0.0 #基金收益
    incomePercent = 0.0 #收益率
    incomeDay = 0.0 #当日收益

class FundTradingData:
    date = ""
    units = 0.0
    cost = 0.0

class FundTradingAnalysis:
    priceDir = ""
    incomeDir = ""
    code = ""
    price = []
    transData = []
    income = []
    tradingData = {}

    def __init__(self, code):
        self.code = code
        self.price = []
        self.tradingData = {}
        self.income = []
        return

    def setBaseDir(self, dir):
        self.priceDir = dir
        return

    def setincomeDir(self, dir):
        self.incomeDir = dir
        return

    def readPriceData(self):
        path = self.priceDir + self.code + ".csv"
        csvReader = csv.reader(open(path, encoding='utf-8'))
        count = 0
        jjjz = 0.0
        ljjz = 0.0
        for line in csvReader:
            count = count + 1
            priceTmp = FundPrice()
            priceTmp.date = getDateFromStr(line[0])
            priceTmp.jjjz = float(line[1])
            priceTmp.ljjz = float(line[2])
            priceTmp.rate = self.calcRate(jjjz, ljjz, priceTmp.ljjz)
            self.price.append(priceTmp)
            jjjz = priceTmp.jjjz
            ljjz = priceTmp.ljjz
            #print(getTimeStr(priceTmp.date), priceTmp.jjjz, priceTmp.ljjz, priceTmp.rate)
        print("read", len(self.price), "price datas")
        return

    def readTradingDataFromDB(self):
        datas = Trading.objects.filter(code=self.code).all().order_by("date")
        if datas == None:
            return
        
        for data in datas:
            tmp = FundTradingData()
            tmp.date = data.date
            tmp.units = data.units
            tmp.cost = data.cost
            self.tradingData[tmp.date] = tmp
            #print("read:", tmp.date, tmp.units, tmp.cost)
        print("read", len(self.tradingData), "trading items")
        return

    # def readTransData(self):
    #     path = self.priceDir + "fund_transaction.csv"
    #     csvReader = csv.reader(open(path, encoding='utf-8'))
    #     lineCount = 0
    #     for line in csvReader:
    #         lineCount = lineCount + 1
    #         if lineCount == 1:
    #             continue

    #         if (len(line) == 0):
    #             continue

    #         if line[0] != self.code:
    #             continue

    #         transDataTmp = FundTradingData()
    #         transDataTmp.date = getTimeStamp(line[1])
    #         transDataTmp.units = float(line[2])
    #         transDataTmp.cost = float(line[3])
    #         self.transData.append(transDataTmp)
    #         #print(line)
    #     return

    def readData(self):
        self.readTradingDataFromDB()
        self.readPriceData()
        return

    def calcRate(self, jjjz, ljjz1, ljjz2):
        if jjjz == 0.0:
            return 0.0

        rate = (ljjz2 - ljjz1) * 100 / jjjz
        return round(rate, 2)

    # 根据交易记录计算收益
    def calcIncome(self):
        units = 0.0
        totalCost = 0.0
        cost = 0.0
        transIncome = 0.0
        lastDayLjjz = 0.0

        for price in self.price:
            incomeDay = 0.0

            # 每日收益
            if lastDayLjjz == 0.0:
                incomeDay = 0.0
            else:
                incomeDay = (price.ljjz - lastDayLjjz) * units
            lastDayLjjz = price.ljjz

            if self.tradingData.__contains__(price.date):
                trading = self.tradingData[price.date]
                # 添加交易数据
                units = units + trading.units
                if trading.units >= 0:
                    totalCost = totalCost + trading.cost
                else :
                    totalCost = cost * units
                    transIncome = transIncome + trading.units * cost - trading.cost

            # for trans in self.transData:
            #     if price.date == trans.date:
            #         # 添加交易数据
            #         units = units + trans.units
            #         if trans.units >= 0:
            #             totalCost = totalCost + trans.cost
            #         else :
            #             totalCost = cost * units
            #             transIncome = transIncome + trans.units * cost - trans.cost
            #             #print("transIncome=", round(transIncome, 3), "trans.cost=", round(trans.cost, 3), "trans.units=", round(trans.units, 3))
            #         #print("buy units=", round(trans.units, 3), "cost=", round(cost, 3), "total units=", round(units, 3), "totalCost=", round(totalCost, 3), "transIncome", round(transIncome, 3))
            #         pass

            # 成本计算:
            # 买入100*10，成本 = 100
            # 第二次买入200*10，成本 = 100*10+200*10 = 3000,平均 = 150
            # 卖出300*10，剩下的成本 = 150*10 = 1500
            income = FundIncome()
            income.units = units
            income.totalCost = totalCost
            if units == 0:
                income.cost = 0.0
            else:
                income.cost = totalCost / units
            cost = income.cost

            # 计算收益
            income.income = price.jjjz * income.units - income.totalCost
            income.incomeTotal = income.income + transIncome
            if income.totalCost > 0:
                income.incomePercent = income.income * 100 / income.totalCost
            else :
                income.incomePercent = 0.0

            # 格式化
            income.income = round(income.income, 2)
            income.totalCost = round(income.totalCost, 2)
            income.incomePercent = round(income.incomePercent, 2)
            income.cost = round(income.cost, 2)
            if income.units == 0.0:
                income.cost = 0.0
            income.units = round(income.units, 2)
            income.incomeTotal = round(income.incomeTotal, 2)
            income.incomeDay = round(incomeDay, 2)

            #print(income.totalCost, income.income, income.incomePercent, income.incomeTotal)

            self.income.append(income)

        #for item in self.income:
        item = self.income[-1]
        print(item.totalCost, item.incomeTotal, item.incomeDay)
        return

    def writeIncomeData(self):
        filename = self.incomeDir + "income_" + self.code + ".csv"
        with open(filename, "w", newline='') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(["date", "jjjz", "ljjz", "rate", "units", "totalCost", \
                "cost", "incomeTotal", "income", "incomePercent", "incomeDay"])

            index = 0
            for price in self.price:
                income = self.income[index]
                writer.writerow([str(price.date), price.jjjz, price.ljjz, price.rate, income.units, income.totalCost,\
                    income.cost, income.incomeTotal, income.income, income.incomePercent, income.incomeDay])
                                
                index = index + 1
        return
    
    def calcYearRate(self):
        # 一年按照254天交易日算，不到一年的数据按照比例计算
        Y1 = 245
        Y3 = 245 * 3
        Y5 = 245 * 5
        count = len(self.price)

        if count == 0:
            return 0.0, 0.0, 0.0

        rateYear1 = 0.0
        rateYear3 = 0.0
        rateYear5 = 0.0

        index = count - 1

        if count < Y1:
            rateYear1 = (self.price[index].ljjz - self.price[0].ljjz) * Y1 * 100 / (count * self.price[0].jjjz)
            rateYear3 = rateYear1 * 3
            rateYear5 = rateYear1 * 5
        elif count < Y3:
            rateYear1 = (self.price[index].ljjz - self.price[count - Y1].ljjz) * 100 / self.price[count - Y1].jjjz
            rateYear3 = (self.price[index].ljjz - self.price[0].ljjz) * Y3 * 100 / (count * self.price[0].jjjz)
            rateYear5 = rateYear3 * 5 / 3
        elif count < Y5:
            rateYear1 = (self.price[index].ljjz - self.price[count - Y1].ljjz) * 100 / self.price[count - Y1].jjjz
            rateYear3 = (self.price[index].ljjz - self.price[count - Y3].ljjz) * 100 / self.price[count - Y3].jjjz
            rateYear5 = (self.price[index].ljjz - self.price[0].ljjz) * Y5 * 100 / (count * self.price[0].jjjz)
        else:
            #print(count, self.price[index].ljjz, self.price[count - Y1].ljjz, self.price[count - Y1].jjjz, getTimeStr(self.price[count - Y1].date))
            rateYear1 = (self.price[index].ljjz - self.price[count - Y1].ljjz) * 100 / self.price[count - Y1].jjjz
            rateYear3 = (self.price[index].ljjz - self.price[count - Y3].ljjz) * 100 / self.price[count - Y3].jjjz
            rateYear5 = (self.price[index].ljjz - self.price[count - Y5].ljjz) * 100 / self.price[count - Y5].jjjz     

        return round(rateYear1, 2), round(rateYear3, 2), round(rateYear5, 2)


# class FundRateMonitor:
#     monitorDay = 10
#     monitorRate1 = MONITOR_RATE_DOWN
#     monitorRate2 = MONITOR_RATE_UP
 
#     monitorResult = []

#     def __init__(self):
#         monitorResult = []
#         return

#     def rateMonitor(self, price):
#         index = len(price) - 1
#         if len(price) < self.monitorDay:
#             return 0.0, False
        
#         rate = (price[index].ljjz - price[index - self.monitorDay].ljjz) * 100 / price[index - self.monitorDay].jjjz
#         rate = round(rate, 2)
#         if rate <= self.monitorRate1 or rate >= self.monitorRate2:
#             print("warning: find rate exception!")
#             return rate, True

#         # 计算最近30个交易日的超阈值增幅
#         if len(price) < 30:
#             return 0.0, False
        
#         curIndex = index
#         for i in range(1, 30):
#             rate = (price[index].ljjz - price[index - 1].ljjz) * 100 / price[index - 1].jjjz
#             rate = round(rate, 2)
#             print("rate ", str(i), ":", rate)


#         return rate, False

#     def monitor(self, price, code):
#         rate, result = self.rateMonitor(price)
#         self.monitorResult.append([code, rate, result])
#         return
    
#     def writeMonitorResult(self, priceDir):
#         filename = priceDir + "monitor_rate.csv"
#         with open(filename, "w", newline='') as csvfile:
#             writer = csv.writer(csvfile)
#             writer.writerow(["code", "rate", "result"])
#             writer.writerows(self.monitorResult)
#         print("write monitor result end.")
#         return

class FundBasicInfo:
    code = ""
    name = ""
    type = ""
    riskLevel = ""
    incomeTotal = 0.0
    income = 0.0
    incomePercent = 0.0
    cost = 0.0

    def __init__(self, code):
        self.code = code
        incomeTotal = 0.0
        income = 0.0
        incomePercent = 0.0
        cost = 0.0
        return

    def getBasicInfo(self, dir):
        path = dir + "funds.csv"
        csvReader = csv.reader(open(path, encoding='utf-8'))
        for item in csvReader:
            if self.code == item[0]:
                self.name = item[1]
                self.type = item[2]
                self.riskLevel = item[3]
                return
        return

def getMonthStr(day):
    tmp = day.split("-")
    return tmp[0] + tmp[1]

def getMonthIncomeNode(date, monthIncome):
    month = getMonthStr(getTimeStr(date))
    for item in monthIncome:
        if item[0] == month:
            return item
    monthIncome.append([month, 0.0])
    index = len(monthIncome) - 1
    return monthIncome[index]

def cmpKeyMonthIncome(monthIncomeNode):
    return monthIncomeNode[0]

# 计算每个月的总收入
def calcMonthIncome(incomeList, fundInfo):
    index = 0
    for item in fundInfo.price:
        node = getMonthIncomeNode(item.date, incomeList)
        node[1] = node[1] + float(fundInfo.income[index].totalCost * item.rate / 100)
        index = index + 1
    return


def writeMonthIncome(incomeList, priceDir):
    incomeList.sort(key=cmpKeyMonthIncome, reverse=False)

    #只保留最近24个月的记录
    count = len(incomeList)
    delCnt = count - 24
    if delCnt > 0:
        del incomeList[0 : delCnt]

    for item in incomeList:
        item[1] = round(item[1], 2)

    filename = priceDir + "month_income.csv"
    with open(filename, "w", newline='') as csvfile:
        writer = csv.writer(csvfile)
        #writer.writerow(["month", "income"])
        writer.writerows(incomeList)
        print("write", len(incomeList),"month income record.")
    return


def writeYearIncome(dir, data):
    filename = dir + "rate_year.csv"
    with open(filename, "w", newline='') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(["code", "rateY1", "rateY3", "rateY5"])
        writer.writerows(data)
        print("write year rate end2.")

def RefreshAllTradingAnalysisData(priceDir, incomeDir):
    allCode = {}
    allFundTrading = []

    tradings = Trading.objects.all()
    for item in tradings:
        if allCode.__contains__(item.code):
            continue

        allCode[item.code] = ""

        # refresh price data first
        from fundinfo.catch_fund_price import getNewData
        getNewData(item.code, priceDir)

        # analysis trading
        analysis = FundTradingAnalysis(item.code)
        analysis.setBaseDir(priceDir)
        analysis.setincomeDir(incomeDir)
        analysis.readData()
        analysis.calcIncome()
        analysis.writeIncomeData()

        # analysis year income
        year1, year3, year5 = analysis.calcYearRate()

        # "code", "rateY1", "rateY3", "rateY5"
        allFundTrading.append([item.code, year1, year3, year5])
        info = FundInfoBriefData()
        #info.refreshFundIncome(code)
        info.refreshYearIncome(year1, year3, year5)
        # # get fund info
        # funds = FundName.objects.filter(code=item.code)
        # if funds == None or len(funds) == 0:
        #     continue
        # fund = funds[0]

        # # "code", "name", "type", "riskLevel", "incomeTotal", "income", "incomePercent", "cost"
        # item = [item.code, fund.name, fund.type, fund.risk, year1, year3, year5]
    writeYearIncome(incomeDir, allFundTrading)
    return


# def calcAll(priceDir):
#     fundList = []
#     path = priceDir + "fund_transaction.csv"
#     csvReader = csv.reader(open(path, encoding='utf-8'))
#     lineCount = 0
#     rateMonitor = FundRateMonitor()
#     fundInfoList = []

#     for line in csvReader:
#         if lineCount == 0:
#             lineCount = lineCount + 1
#             continue

#         if (len(line) == 0):
#             continue

#         find = False
#         fundCode = line[0]
#         for code in fundList:
#             if fundCode == code:
#                 find = True
#                 break
#         if find == True:
#             continue

#         fundList.append(fundCode)
#         basicInfo = FundBasicInfo(fundCode)
#         basicInfo.getBasicInfo(priceDir)
#         fundInfoList.append(basicInfo)

#     rateYear = []
#     incomeMonthList = []

#     for code in fundList:
#         print("calc income, code =", code)
#         fundInfo = FundInfo(code)
#         fundInfo.setBaseDir(priceDir)
#         fundInfo.readData()
#         fundInfo.calcIncome()
#         fundInfo.writeIncomeData()

#         # 计算年收益
#         rateY1, rateY3, rateY5 = fundInfo.calcYearRate()
#         rateYear.append([code, rateY1, rateY3, rateY5])

#         # 监控涨跌阈值
#         rateMonitor.monitor(fundInfo.price, code)

#         # 计算月收益
#         calcMonthIncome(incomeMonthList, fundInfo)

#         for item in fundInfoList:
#             if item.code == code:
#                 if len(fundInfo.income) == 0:
#                     continue
#                 index = len(fundInfo.income) - 1
#                 income = fundInfo.income[index]
#                 item.incomeTotal = income.incomeTotal
#                 item.income = income.income
#                 item.incomePercent = income.incomePercent
#                 item.cost = income.totalCost
#                 #print(item.cost)

#     filename = priceDir + "rate_year.csv"
#     with open(filename, "w", newline='') as csvfile:
#         writer = csv.writer(csvfile)
#         writer.writerow(["code", "rateY1", "rateY3", "rateY5"])
#         writer.writerows(rateYear)
#         print("write year rate end.")

#     filename = priceDir + "index_info.csv"
#     with open(filename, "w", encoding='utf-8', newline='') as csvfile:
#         writer = csv.writer(csvfile)
#         writer.writerow(["code", "name", "type", "riskLevel", "incomeTotal", "income", "incomePercent", "cost"])
#         for item in fundInfoList:
#             writer.writerow([item.code, item.name, item.type, item.riskLevel,\
#                  item.incomeTotal, item.income, item.incomePercent, item.cost])
#         print("write index info end.")

#     rateMonitor.writeMonitorResult(priceDir)
#     writeMonthIncome(incomeMonthList, priceDir)
#     return
        

# if __name__ == '__main__':
#     if sys.argv == None:
#         print("python calc.py basedir code")

#     dir = sys.argv[1]

#     if sys.argv[2] == "all":
#         calcAll(dir)
#     else:
#         code = sys.argv[2]

#         fundInfo = FundInfo(code)
#         fundInfo.setBaseDir(dir)
#         fundInfo.readData()
#         fundInfo.calcIncome()
#         fundInfo.writeIncomeData()

